package com.yourcompany.service.impl;

import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yourcompany.api.dto.UserLoginDTO;
import com.yourcompany.api.dto.UserQueryDTO;
import com.yourcompany.api.entity.LoginLog;
import com.yourcompany.api.entity.User;
import com.yourcompany.api.mapper.UserMapper;
import com.yourcompany.api.service.LoginLogService;
import com.yourcompany.api.service.UserService;
import com.yourcompany.api.vo.UserVO;
import com.yourcompany.common.exception.BusinessException;
import com.yourcompany.api.config.UserProperties;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.yourcompany.common.utils.WebUtils;
import com.yourcompany.api.event.LoginEvent;
import com.yourcompany.api.enums.LoginEventEnum;
import com.yourcompany.api.dto.CreditActivateDTO;
import com.yourcompany.api.service.CreditPayService;
import com.yourcompany.api.entity.CreditPay;
import java.math.BigDecimal;

import java.time.LocalDateTime;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private UserProperties userProperties;


    @Autowired
    private ApplicationEventPublisher eventPublisher;

    @Autowired
    private CreditPayService creditPayService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String login(UserLoginDTO loginDTO) {
        try {
            // 校验登录参数
            validateLoginParams(loginDTO);
            
            // 获取用户信息
            User user = getUserByLoginDTO(loginDTO);
            
            // 校验用户状态
            validateUserStatus(user, loginDTO);
            
            // 校验密码
            validatePassword(user, loginDTO);
            
            // 生成token
            StpUtil.login(user.getId());
            String token = StpUtil.getTokenValue();
            
            // 更新登录信息
            updateLoginInfo(user, loginDTO);
            
            // 发布登录成功事件
            publishLoginEvent(user, loginDTO, LoginEventEnum.LOGIN_SUCCESS);
            
            return token;
        } catch (BusinessException e) {
            // 业务异常已经发布了对应的登录事件，这里直接抛出
            throw e;
        } catch (Exception e) {
            // 系统异常，发布登录失败事件
            log.error("登录异常", e);
            publishLoginEvent(null, loginDTO, LoginEventEnum.LOGIN_FAILED, "系统异常");
            throw new BusinessException("系统繁忙，请稍后重试");
        }
    }

    private void validateLoginParams(UserLoginDTO loginDTO) {
        if (StringUtils.isBlank(loginDTO.getUsername()) 
                && StringUtils.isBlank(loginDTO.getPhone())) {
            throw new BusinessException("请输入用户名或手机号");
        }
    }

    private User getUserByLoginDTO(UserLoginDTO loginDTO) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(loginDTO.getUsername())) {
            queryWrapper.eq(User::getUsername, loginDTO.getUsername());
        } else {
            queryWrapper.eq(User::getPhone, loginDTO.getPhone());
        }
        return getOne(queryWrapper);
    }

    private void validateUserStatus(User user, UserLoginDTO loginDTO) {
        if (user == null) {
            publishLoginEvent(null, loginDTO, LoginEventEnum.ACCOUNT_NOT_FOUND);
            throw new BusinessException(LoginEventEnum.ACCOUNT_NOT_FOUND.getMessage());
        }
        
        if (user.getStatus() == 0) {
            publishLoginEvent(user, loginDTO, LoginEventEnum.ACCOUNT_DISABLED);
            throw new BusinessException(LoginEventEnum.ACCOUNT_DISABLED.getMessage());
        }
    }

    private void validatePassword(User user, UserLoginDTO loginDTO) {
        if (!BCrypt.checkpw(loginDTO.getPassword(), user.getPassword())) {
            publishLoginEvent(user, loginDTO, LoginEventEnum.PASSWORD_ERROR);
            throw new BusinessException(LoginEventEnum.PASSWORD_ERROR.getMessage());
        }
    }

    private void publishLoginEvent(User user, UserLoginDTO loginDTO, LoginEventEnum eventEnum) {
        publishLoginEvent(user, loginDTO, eventEnum, eventEnum.getMessage());
    }

    private void publishLoginEvent(User user, UserLoginDTO loginDTO, 
            LoginEventEnum eventEnum, String message) {
        LoginEvent event = LoginEvent.builder()
            .source(this)
            .username(user != null ? user.getUsername() : loginDTO.getUsername())
            .userId(user != null ? user.getId() : null)
            .loginType("account")
            .deviceId(loginDTO.getDeviceId())
            .userAgent(loginDTO.getUserAgent())
            .status(eventEnum.getStatus())
            .msg(message != null ? message : eventEnum.getMessage())
            .build();
        
        eventPublisher.publishEvent(event);
    }

    /**
     * 更新用户登录信息
     */
    private void updateLoginInfo(User user, UserLoginDTO loginDTO) {
        user.setLastLoginTime(LocalDateTime.now());
        user.setLastLoginIp(WebUtils.getIpAddr());
        user.setDeviceId(loginDTO.getDeviceId());
        user.setPushToken(loginDTO.getPushToken());
        updateById(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void register(UserLoginDTO registerDTO) {
        // 检查用户名是否已注册
        if (StringUtils.isNotBlank(registerDTO.getUsername())) {
            if (count(new LambdaQueryWrapper<User>()
                    .eq(User::getUsername, registerDTO.getUsername())
                    ) > 0) {
                throw new BusinessException("用户名已注册");
            }
        }
        
        // 检查手机号是否已注册
        if (StringUtils.isNotBlank(registerDTO.getPhone())) {
            if (count(new LambdaQueryWrapper<User>()
                    .eq(User::getPhone, registerDTO.getPhone())
                    ) > 0
            ) {
                throw new BusinessException("手机号已注册");
            }
        }
        
        // 创建用户
        User user = new User();
        user.setUsername(registerDTO.getUsername());
        user.setPhone(registerDTO.getPhone());
        
        // 处理密码
        String password = registerDTO.getPassword();
        if (StringUtils.isBlank(password)) {
//            // 如果密码为空，使用默认密码
//            if (StringUtils.isNotBlank(registerDTO.getPhone())) {
//                // 如果有手机号，使用手机号后6位
//                password = registerDTO.getPhone().substring(Math.max(0, registerDTO.getPhone().length() - 6));
//            } else {
//                // 否则使用配置的默认密码
//
//            }
            password = userProperties.getDefaultPassword();
        }
        user.setPassword(BCrypt.hashpw(password));
        
        user.setStatus(1);
        user.setDeviceId(registerDTO.getDeviceId());
        user.setPushToken(registerDTO.getPushToken());
        user.setRegisterIp(registerDTO.getDeviceId());
        user.setRegisterSource("app");
        
        save(user);
    }

    @Override
    public void updatePassword(Long userId, String oldPassword, String newPassword) {
        User user = getById(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }
        
        if (!BCrypt.checkpw(oldPassword, user.getPassword())) {
            throw new BusinessException("原密码错误");
        }
        
        user.setPassword(BCrypt.hashpw(newPassword));
        updateById(user);
    }

    @Override
    public void resetPassword(String phone) {
        User user = getOne(new LambdaQueryWrapper<User>()
                .eq(User::getPhone, phone));
        
        if (user == null) {
            throw new BusinessException("用户不存在");
        }
        
        // TODO: 发送短信验证码
        // TODO: 验证短信验证码
        // TODO: 重置密码
    }

    @Override
    public User getCurrentUser() {
        Long loginId = StpUtil.getLoginIdAsLong();
        return getById(loginId);
    }

    @Override
    public IPage<UserVO> pageUsers(IPage<User> page, UserQueryDTO queryDTO) {
        // 构建查询条件
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        
        if (StringUtils.isNotBlank(queryDTO.getUsername())) {
            queryWrapper.like(User::getUsername, queryDTO.getUsername());
        }
        if (StringUtils.isNotBlank(queryDTO.getPhone())) {
            queryWrapper.like(User::getPhone, queryDTO.getPhone());
        }
        if (StringUtils.isNotBlank(queryDTO.getNickname())) {
            queryWrapper.like(User::getNickname, queryDTO.getNickname());
        }
        if (queryDTO.getStatus() != null) {
            queryWrapper.eq(User::getStatus, queryDTO.getStatus());
        }
        if (queryDTO.getIsVerified() != null) {
            queryWrapper.eq(User::getIsVerified, queryDTO.getIsVerified());
        }
        
        // 查询数据
        IPage<User> userPage = page(page, queryWrapper);
        // 获取数据总数
        long total = userPage.getTotal();
        
        // 转换为VO
        IPage<UserVO> convert = userPage.convert(user -> {
            UserVO vo = new UserVO();
            BeanUtils.copyProperties(user, vo);


            // 处理手机号
            if (StringUtils.isNotBlank(vo.getPhone())) {
                vo.setPhone(vo.getPhone().replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2"));
            }

            return vo;
        });
        convert.setTotal(total);
        return convert;
    }

    @Override
    public void activateCredit(CreditActivateDTO activateDTO) {
        // 检查用户信息
        User user = getById(activateDTO.getUserId());
        if (user == null) {
            throw new BusinessException("用户不存在");
        }
        
        // 检查用户实名认证
        if (!user.getIsVerified()) {
            throw new BusinessException("请先完成实名认证");
        }
        
        // 开通先充后付
        creditPayService.activate(activateDTO);
    }
    
    @Override
    public CreditPay getCreditInfo(Long userId) {
        return creditPayService.getById(userId);
    }
    
    @Override
    public boolean checkCreditAvailable(Long userId) {
        return creditPayService.checkCreditAvailable(userId, BigDecimal.ZERO);
    }
} 